import store from '../store/index.js';
import i18n from "../common/i18n/index.js";

var Graph = function (ctx, ctx_axis) {
    this.height = 500;
    this.width = 800;

    this.ctx = ctx;//图表层canvas对象
    this.ctx_axis = ctx_axis;//坐标轴层canvas对象

    this.axisXColor = '#A8A8A8';//坐标颜色配置
    this.axisYColor = '#A8A8A8';
    this.scaleXColor = '#fff';//刻度颜色配置
    this.scaleYColor = '#fff';
    this.scaleFont = 13;

    this.info = {//当前数据信息配置
        color: '#39FFBE',
        font: 34
    }

    this.data = [];

    this.dataArrLen = 100;//绘制路线数组长度
    this.value = 1.5;//设置最终爆炸点

    this.lineWidth = 1;//曲线宽度

    this.lineColor = 'rgba(255, 220, 59, .8)';//曲线颜色
    this.areaColor = ['rgba(255, 220, 59, .1)','rgba(255, 130, 18, .1)'];//填充颜色

    this.pathBg = {//是否填充颜色
        show: true
    }

    //动画延时
    this.timer = null;
    this.delay = {
        isDelay: true,
        time: 20
    }

    this.userAgent = 'pc';//当前设备类型
    this.distant = 30;//坐标轴最大值与图形的间隙
    this.space = 55;//坐标轴与画布边缘间距

    this.mul = 2;//canvas倍数

}

Graph.prototype.initAxis = function(){
    this.initData();
    this.drawAxis();
}

Graph.prototype.init = function () {//初始化图表
    this.initData();
    this.drawAxis();
    this.drawAnimation(this.ctx);
}

Graph.prototype.initData = function(){//初始化数据
    clearInterval(this.timer)
    this.ctx_axis.clearRect(0, 0, this.width, this.height);

    this.lenAxisX = this.width - this.space;//坐标长度
    this.lenAxisY = this.height - 40;
    this.percent = 3;//控制动画绘制节奏
    this.scaleX = 10*this.mul;
    this.scaleY = 200*this.mul;
    //Y轴初始刻度配置
    this.scaleYLen = {
        maxLen: 2,//初始最大刻度
        start: 1,//Y轴初始刻度
        maxY: 1,//Y轴含起伏，当前获取到的最大的Y轴数据，便于判断当前Y坐标轴的刻度
        unit:1
    }
    //X轴初始刻度配置
    this.scaleXLen = {
        maxLen: 4,//初始最大刻度
        pxLen: 10,//单位刻度大小比例，x轴为时间刻度单位刻度大小根据动画绘制延时决定
        unit: 1,//每隔几个单位显示
    }
    this.lineWidth = 1 * this.mul;
    this.scaleFont = 13 * this.mul;
    this.info.font = 35 * this.mul;
    
    //随机生成倍数
    this.value = (Math.random()*1-0.5)>0?Math.floor(Math.random()*20+10)/10:Math.floor(Math.random()*120+20)/10;
    // this.value = Math.floor(Math.random()*120+60)/10
    // this.value = 58
    
    this.data = this.getDataArr();
}

Graph.prototype.gameBetween = function(){//游戏开始前的准备时间
    let time = 6000;
    let timer = setInterval(() => {
        if(time === 0){
            store.commit('setGameState',0);
            clearInterval(timer)
        }
        this.ctx.clearRect(0, 0, this.width, this.height);
        this.drawText({
            ctx: this.ctx,
            text: i18n.t("game.start1") + (time/1000).toFixed(1) + 's' + i18n.t("game.start2"),
            font: '36px 黑体',
            fontColor: '#FFCF37'
        })
        time -= 100;
    }, 100);
}

//绘制坐标轴
Graph.prototype.drawAxis = function () {
    this.ctx_axis.clearRect(0, 0, this.width, this.height);
    this.drawLine(this.ctx_axis, { x: this.space, y: this.space }, { x: this.lenAxisX, y: this.space }, this.axisXColor);
    this.drawLine(this.ctx_axis, { x: this.space, y: this.space }, { x: this.space, y: this.lenAxisY }, this.axisYColor);

    //X轴刻度设置
    this.ctx_axis.beginPath();
    this.ctx_axis.fillStyle = this.scaleXColor;
    this.ctx_axis.lineWidth = this.lineWidth/2;
    this.ctx_axis.textAlign = "center";
    this.ctx_axis.font = this.scaleFont + 'px 黑体';
    for (let i = 0; i < this.scaleXLen.maxLen / this.scaleXLen.unit; i++) {//每隔几个刻度打印一次
        this.ctx_axis.fillText(i * this.scaleXLen.unit * 4, this.scaleX * i * this.scaleXLen.unit * this.scaleXLen.pxLen + this.space, this.height - 10)
    }
    this.ctx_axis.closePath();

    //Y轴刻度设置
    this.ctx_axis.beginPath();
    this.ctx_axis.fillStyle = this.scaleYColor;
    this.ctx_axis.lineWidth = 0.5;
    this.ctx_axis.textAlign = "right";
    this.ctx_axis.font = this.scaleFont + 'px 黑体';
    for (let i = 1; i <= this.scaleYLen.maxLen / this.scaleYLen.unit; i++) {
        this.ctx_axis.fillText(i*this.scaleYLen.unit + 1 + 'x', this.space-4, this.height - this.space - this.scaleY * i * this.scaleYLen.unit)
    }
    this.ctx_axis.closePath();
}

//绘制直线
Graph.prototype.drawLine = function (ctx, start, end, color) {
    ctx.beginPath();
    ctx.strokeStyle = color;
    ctx.lineWidth = 1;
    ctx.moveTo(start.x, this.height - start.y);
    ctx.lineTo(end.x, this.height - end.y);
    ctx.stroke();
    ctx.closePath()
}

//绘制文字
Graph.prototype.drawText = function ({ ctx, text, x = this.width / 2, y = this.lenAxisY / 2 + 20, font = this.info.font+'px 黑体', fontColor = this.info.color }) {
    ctx.beginPath();
    ctx.font = font;
    ctx.fillStyle = fontColor;
    ctx.textAlign = "center";
    ctx.fillText(text, x, y);
    ctx.closePath();
}

//动画效果
Graph.prototype.drawAnimation = function (ctx) {
    this.drawAxis();
    ctx.beginPath();
    this.drawPath(ctx, this.toParseData(this.data.slice(0, this.percent), this.scaleX, this.scaleY));
    ctx.stroke();

    this.percent = this.percent + 1;
    if (this.percent > this.dataArrLen) {
        ctx.closePath();
        
        this.ctx.clearRect(0, 0, this.width, this.height);
        this.drawText({
            ctx: this.ctx,
            text: i18n.t("game.boom") + '@' + (this.value).toFixed(2) + 'x',
            font: '46px bold 黑体',
            fontColor: '#EB6044'
        });
        store.commit('setGameState',2);
        
        setTimeout(() => {
            store.commit('setGameState',3);
            this.gameBetween();//游戏结束后下一局开始前的准备时间
        }, 5000);

        return
    }

    //目前数组内的x一个单位为this.scaleX个像素，一个时间刻度为10个单位(pxLen)
    // if (this.data[this.percent - 1].x / this.scaleXLen.pxLen > this.scaleXLen.maxLen) {
    if(this.data[this.percent-1].x*this.scaleX > this.lenAxisX-this.distant){
        this.scaleXLen.maxLen = this.data[this.percent - 1].x / this.scaleXLen.pxLen;
        this.scaleX = (this.lenAxisX - this.distant) / (this.data[this.percent - 1].x);
        
        if(this.scaleX*10*this.scaleXLen.unit <= 100){
            this.scaleXLen.unit *= 2;
        }
    }
    //如果最新的y数据大于当前的最大刻度，则将最大的数据作为标准，重新生成y轴的刻度，如果后期的数据低于最大的数据，刻度不变化
    if (this.data[this.percent - 1].y > this.scaleYLen.maxY-1) {
    // if(this.data[this.percent-1].y*this.scaleY > this.scaleYLen.maxY*this.scaleY-this.distant){
        this.scaleYLen.maxY = this.data[this.percent - 1].y;//存储最大值
        this.scaleYLen.maxLen = Math.ceil(this.data[this.percent - 1].y);//最大刻度
        this.scaleY = (this.lenAxisY - this.distant) / (this.data[this.percent - 1].y + 1);//只要当前值大于最大值就更新刻度

        if(this.scaleY*this.scaleYLen.unit <= 100){
            this.scaleYLen.unit *= 2;
        }
        
    }

    if (this.delay.isDelay) {//动画延时
        this.timer = setTimeout(() => {
            if (this.percent > this.dataArrLen) {
                clearTimeout(this.timer);
            }
            this.drawAnimation(ctx)
        }, this.delay.time)
    } else {
        window.requestAnimationFrame(this.drawAnimation.bind(this, ctx));//bind修改this指向
    }


}

//颜色填充
Graph.prototype.drawPathColor = function (ctx, point, points) {
    let int = 0;
    for (let i = 0; i < points.length - 1; i++) {
        ctx.beginPath();
        if (i == 0) {
            ctx.moveTo(points[0].x, points[0].y);
            ctx.quadraticCurveTo(point[0].x, point[0].y, points[1].x, points[1].y);
            int = int + 1;
        }
        else if (i < points.length - 2) {
            ctx.moveTo(points[i].x, points[i].y);
            ctx.bezierCurveTo(point[int].x, point[int].y, point[int + 1].x, point[int + 1].y, points[i + 1].x, points[i + 1].y);
            int += 2;
        }
        else if (i == points.length - 2) {
            ctx.moveTo(points[points.length - 2].x, points[points.length - 2].y);
            ctx.quadraticCurveTo(point[point.length - 1].x, point[point.length - 1].y, points[points.length - 1].x, points[points.length - 1].y);
        }
        ctx.lineTo(points[i + 1].x, this.height - this.space);
        ctx.lineTo(points[i].x, this.height - this.space);
        this.drawAreaColor(ctx);
        ctx.closePath();
    }
}

// 绘制线性图表颜色填充
Graph.prototype.drawAreaColor = function (ctx) {
    let grd = ctx.createLinearGradient(0, this.height, this.width, this.height);
    grd.addColorStop(0, this.areaColor[0]);
    grd.addColorStop(1, this.areaColor[1]);
    ctx.fillStyle = grd;
    ctx.fill();
}

//绘制曲线
Graph.prototype.drawGraphLine = function (ctx, point, points) {
    ctx.beginPath();
    ctx.strokeStyle = this.lineColor;
    ctx.lineWidth = this.lineWidth;

    let int = 0;
    for (let i = 0; i < points.length; i++) {
        if (i == 0) {
            ctx.moveTo(points[0].x, points[0].y);
            ctx.quadraticCurveTo(point[0].x, point[0].y, points[1].x, points[1].y);
            int = int + 1;
        }
        else if (i < points.length - 2) {
            ctx.moveTo(points[i].x, points[i].y);
            ctx.bezierCurveTo(point[int].x, point[int].y, point[int + 1].x, point[int + 1].y, points[i + 1].x, points[i + 1].y);
            int += 2;
        }
        else if (i == points.length - 2) {
            ctx.moveTo(points[points.length - 2].x, points[points.length - 2].y);
            ctx.quadraticCurveTo(point[point.length - 1].x, point[point.length - 1].y, points[points.length - 1].x, points[points.length - 1].y);
        }
    }
    ctx.stroke();
    ctx.closePath();
}

//线条绘制
Graph.prototype.drawPath = function (ctx, path) {
    ctx.clearRect(0, 0, this.width, this.height);
    let point = this.getControlPoint(path);//获取控制点
    let points = path;

    this.drawGraphLine(this.ctx, point, points);//绘制曲线

    if (this.pathBg.show) {
        this.drawPathColor(this.ctx, point, points);//绘制填充颜色
    }

    if (points.length > 1) {
        ctx.beginPath();
        ctx.arc(points[points.length - 1].x, points[points.length - 1].y, 3, 0, 2 * Math.PI);
        ctx.fillStyle = this.lineColor;
        ctx.fill();
        ctx.closePath();

        this.drawText({
            ctx,
            text: ((this.data[this.percent - 1]).y).toFixed(2) + 'x'
        })
        store.commit('setNowTimes',((this.data[this.percent - 1]).y).toFixed(2));
    }
}

//将数据转换为canvas像素坐标
Graph.prototype.toParseData = function (data, scaleX, scaleY) {
    let arr = [];
    for (let i = 0; i < data.length; i++) {
        arr.push({
            x: data[i].x * scaleX + this.space,
            y: this.height - (data[i].y-1) * scaleY - this.space
        })
    }
    return arr
}

//根据最终爆炸点推算坐标点路线
Graph.prototype.getDataArr = function () {//路线从1开始(0,1) y=x*x+1
    
    this.dataArrLen = 100*Math.floor(this.value);
    
    let boom = this.value - 1, arr = [];
    let len = Math.sqrt(boom* 200);
    for (let i = 0; i < this.dataArrLen - 1; i++) {
        arr.push({
            x: len / this.dataArrLen * i,
            y: (len / this.dataArrLen * i) * (len / this.dataArrLen * i) / 200 + 1
        })
    }
    arr.push({
        x: len,
        y: this.value
    })
    return arr
}

//获取控制点
Graph.prototype.getControlPoint = function (path) {
    let rt = 0.3, i = 0, count = path.length - 2, arr = [];
    for (; i < count; i++) {
        let a = path[i], b = path[i + 1], c = path[i + 2];
        let v1 = new Vector2(a.x - b.x, a.y - b.y);
        let v2 = new Vector2(c.x - b.x, c.y - b.y);
        let v1Len = v1.length(), v2Len = v2.length();
        let centerV = v1.normalize().add(v2.normalize()).normalize();
        let ncp1 = new Vector2(centerV.y, centerV.x * -1);
        let ncp2 = new Vector2(centerV.y * -1, centerV.x);
        if (ncp1.angle(v1) < 90) {
            let p1 = ncp1.multiply(v1Len * rt).add(b);
            let p2 = ncp2.multiply(v2Len * rt).add(b);
            arr.push(p1, p2)
        }
        else {
            let p1 = ncp1.multiply(v2Len * rt).add(b);
            let p2 = ncp2.multiply(v1Len * rt).add(b);
            arr.push(p2, p1)
        }
    }
    return arr;
}

//向量计算方法
var Vector2 = function (x, y) {
    this.x = x;
    this.y = y;
};
Vector2.prototype = {
    "length": function () {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    },
    "normalize": function () {
        var inv = 1 / this.length();
        return new Vector2(this.x * inv, this.y * inv);
    },
    "add": function (v) {
        return new Vector2(this.x + v.x, this.y + v.y);
    },
    "multiply": function (f) {
        return new Vector2(this.x * f, this.y * f);
    },
    "dot": function (v) {
        return this.x * v.x + this.y * v.y;
    },
    "angle": function (v) {
        return Math.acos(this.dot(v) / (this.length() * v.length())) * 180 / Math.PI;
    }
};

export default Graph